/* 
 * File:   RepositorioPoller.cpp
 * Author: maximiliano
 * 
 * Created on May 14, 2013, 6:05 PM
 */

#include <vector>

#include "client_RepositorioPoller.h"
#include "common_MutexScopeLocker.h"

RepositorioPoller::RepositorioPoller(Repositorio* pRepositorio, uint32_t pIntervaloPoleo) {
    _intervaloPoleo = pIntervaloPoleo;
    _repositorio = pRepositorio;
    _poleando = false;
}

void RepositorioPoller::setRepositorioPollerManejadorEvento (IRepositorioPollerManejadorEvento* pManejadorEventos){
   this->manejadorEvento = pManejadorEventos;
}

RepositorioPoller::~RepositorioPoller() {}

void RepositorioPoller::Iniciar() throw (Excepcion&){

    try
    {
        FileUtils f_utils;
        
        if (!f_utils.DirectorioExistente (this->_repositorio->GetPath()))
        {
            string msg = "Fallo al iniciar el poller.  Directorio \" ";
            msg += this->_repositorio->GetPath();
            msg += "\" inexistente.";
            
            throw Excepcion (msg);
        }
        
        setPoleando(true);
        
        Thread::Iniciar();
    }
    catch (Excepcion &ex)
    {
        throw ex;
    }
}

void RepositorioPoller::Finalizar() throw (Excepcion&){
    
    try
    {
        if (getPoleando())
        {
            setPoleando(false);

            Thread::Finalizar();
        }
    }
    catch (Excepcion &ex)
    {
        throw ex;
    }
}

void RepositorioPoller::tarea (){
    
    FileUtils f_utils;
    
    while(_poleando)
    {        
        LNombreArchivo lista_inicial;
        
        if (!f_utils.ObtenerNombreArchivos(this->_repositorio->GetPath(), lista_inicial))
        {
            /* Es un error crítico.  No se pudo obtener la lista de archivos contenidos
             * en el repositorio.  Asiendo el error en el log y finalizo la tarea
             * de polling.
             */
            setPoleando(false);
        }
        
        /* Para todo archivo en el repositorio fisico, se evalua el estado del archivo
         * respecto del estado anterior declarado en el respositorio.
         */
        LNombreArchivo::iterator it;
        for(it = lista_inicial.begin(); it != lista_inicial.end(); it++)
        {       
            evaluarArchivo(*it);
        }
        usleep(this->_intervaloPoleo);
    }
}

void RepositorioPoller::evaluarArchivo(const string& pNombreArchivo){
    
    if (esArchivoNuevo(pNombreArchivo))
    {
        this->manejadorEvento->archivoNuevoEvento(pNombreArchivo);
    }
    else if (esArchivoModificado(pNombreArchivo))
    {
        this->manejadorEvento->archivoModificadoEvento(pNombreArchivo);
    }
}

void RepositorioPoller::setPoleando(const bool pValor){
    
    MutexScopeLocker _locker (_poleandoMutex);
    _poleando = pValor;
}

bool RepositorioPoller::getPoleando(){
    MutexScopeLocker _locker (_poleandoMutex);
    return _poleando;
}

bool RepositorioPoller::esArchivoNuevo(const string &pNombreArchivo){

    /* Se asume que pNombreArchivo es el nombre de un archivo alojado en el
     * el repositorio AU.
     * 
     * Un archivo es nuevo cuando figura fisicamente en el directorio AU pero no 
     * figura en el repositorio.
     * 
     */
    return !_repositorio->ExisteRepoItem(pNombreArchivo);
}

bool RepositorioPoller::esArchivoModificado(const string &pNombreArchivo){

    /* Se asume que pNombreArchivo es el nombre de un archivo alojado en el
     * repositorio AU.
     * 
     * Un archivo es modificado si para alguno de sus chunks calculados, el hash
     * difiere del hash asociado al chunk según el repositorio.
     * 
     */
    
    RepoItem* item = _repositorio->GetRepoItemByFilename(pNombreArchivo);
    string rutaCompletaArchivo = item->GetRutaCompletaArchivo ();
    FileUtils fileUtils;
    size_t cantidadChunks = fileUtils.CalcularCantidadChunks(rutaCompletaArchivo);
    bool modificado = (item->GetCantidadHashes() ==  cantidadChunks);
    
    for (size_t i = 0; i <  cantidadChunks && !modificado; i++)
    {
        modificado = (item->GetHash(i) != fileUtils.GetHash (rutaCompletaArchivo, i));
    }

    return modificado;
}